/*******************************************************************************
 * Copyright (c) 2014 lifeng (lifengsofts@gmail.com)
 * See the file licenses/license.txt for copying permission.
 ******************************************************************************/
package cn.woblog.android.httputils.callback;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.ParseException;
import org.apache.http.util.EntityUtils;

import cn.woblog.android.httputils.exception.AppException;
import cn.woblog.android.httputils.exception.AppException.Type;
import cn.woblog.android.httputils.utils.Consts;
import cn.woblog.android.httputils.utils.Logs;
import cn.woblog.android.httputils.utils.StreamTools;

import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;

public abstract class AbstractCallback<T> implements ICallback<T> {
	private static final String TAG = "AbstractCallback";
	/**
	 * save to file paht
	 */
	protected String path;
	protected boolean isShowProgress;
	protected boolean isCancel;
	private int mContentLengt;
	private Message message;
	private Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			onProgress(msg.arg1, mContentLengt);
		};
	};

	protected void checkIfIsCancel() throws AppException {
		if (isCancel) {
			throw new AppException(Type.CanceledException,
					"this request has been cancel");
		}
	}

	public void onProgress(int curentPos, int totalPos) {
	}

	@Override
	public boolean onCustomParams(OutputStream out) {
		return false;
	}

	@Override
	public T handle(HttpURLConnection connection) throws AppException {

		try {
			checkIfIsCancel();
			mContentLengt = (int) connection.getContentLength();
			switch (connection.getResponseCode()) {
			case HttpStatus.SC_OK:
				InputStream content = connection.getInputStream();
				if (!TextUtils.isEmpty(path)) {
					byte[] bf = new byte[2048];
					int len = 0;
					int currentPos = 0;
					FileOutputStream fileOutputStream = new FileOutputStream(
							path);
					while ((len = content.read(bf)) != -1) {
						checkIfIsCancel();
						if (isShowProgress) {
							currentPos += len;
							message = Message.obtain();
							message.arg1 = currentPos;
							handler.sendMessage(message);
							// Logs.d(TAG, "download + progress:" + currentPos);
						}
						fileOutputStream.write(bf, 0, len);
					}
					fileOutputStream.close();
					return bindData(path);
				} else {
					checkIfIsCancel();
					return bindData(StreamTools.readInputStream(content));
				}
			default:
				break;
			}
		} catch (FileNotFoundException e) {
			throw new AppException(Type.FileNotFoundException, e.getMessage());
			// e.printStackTrace();
		} catch (IllegalStateException e) {
			throw new AppException(Type.IllegalStateException, e.getMessage());
			// e.printStackTrace();
		} catch (ParseException e) {
			throw new AppException(Type.ParseException, e.getMessage());
			// e.printStackTrace();
		} catch (IOException e) {
			throw new AppException(Type.IOException, e.getMessage());
			// e.printStackTrace();
		}
		return null;

	}

	@Override
	public T handle(HttpResponse response) throws AppException {
		try {
			checkIfIsCancel();
			HttpEntity entity = response.getEntity();
			mContentLengt = (int) entity.getContentLength();
			switch (response.getStatusLine().getStatusCode()) {
			case HttpStatus.SC_OK:
				if (!TextUtils.isEmpty(path)) {
					byte[] bf = new byte[2048];
					int len = 0;
					int currentPos = 0;
					FileOutputStream fileOutputStream = new FileOutputStream(
							path);
					InputStream content = entity.getContent();
					while ((len = content.read(bf)) != -1) {
						checkIfIsCancel();
						if (isShowProgress) {
							currentPos += len;
							message = Message.obtain();
							message.arg1 = currentPos;
							handler.sendMessage(message);
							// Logs.d(TAG, "download + progress:" + currentPos);
						}
						fileOutputStream.write(bf, 0, len);
					}
					fileOutputStream.close();
					return bindData(path);
				} else {
					checkIfIsCancel();
					return bindData(EntityUtils.toString(entity,
							Consts.RESPONSE_DEFAULT_CHARSET));
				}
			default:
				break;
			}
		} catch (FileNotFoundException e) {
			throw new AppException(Type.FileNotFoundException, e.getMessage());
			// e.printStackTrace();
		} catch (IllegalStateException e) {
			throw new AppException(Type.IllegalStateException, e.getMessage());
			// e.printStackTrace();
		} catch (ParseException e) {
			throw new AppException(Type.ParseException, e.getMessage());
			// e.printStackTrace();
		} catch (IOException e) {
			throw new AppException(Type.IOException, e.getMessage());
			// e.printStackTrace();
		}
		return null;
	}

	abstract protected T bindData(String string);

	public void onCanceled() {
	};

	@Override
	public T preRequest() {
		return null;
	}

	@Override
	public T postRequest(T t) {
		return t;
	}

	public AbstractCallback<T> setProgress(boolean isShowProgress) {
		this.isShowProgress = isShowProgress;
		return this;
	}

	public AbstractCallback<T> cache(String path) {
		this.path = path;
		return this;
	}

	@SuppressWarnings("resource")
	protected T save2File(InputStream content, int contentLength)
			throws IOException {
		return null;
	}

	@Override
	public void cancel() {
		isCancel = true;
	}
}
